package com.boco.web;

import com.boco.common.entity.Account;
import com.boco.common.entity.OperateLog;
import com.boco.common.util.CaptchaUtils;
import com.boco.common.util.Utils;
import com.boco.config.SMSConfig;
import com.boco.domain.OperateLogRepository;
import com.boco.service.LoginService;
import com.boco.service.SmsService;
import com.boco.service.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.shiro.SecurityUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

//import org.springframework.web.bind.annotation.ResponseStatus;

/**
 * @author pandengke/pdkkpdk@163.com
 * @date 2018/9/29
 */

@Api(tags = "用户登录相关接口服务")
@RestController
@RequestMapping("/login")
public class LoginController extends BaseController {

    @Resource
    private UserService userService;

    @Resource
    private LoginService loginService;


    @Resource
    OperateLogRepository operateLogRepository;

    @Resource
    private SmsService smsService;

    /**
     * 图片验证码,
     */
    @GetMapping(value = "/imageCode")
    @ApiOperation(value = "获取图片验证码", notes = "流的形式返回图片")
    public void getImageCode(HttpServletResponse response) throws IOException {
        response.setContentType("image/jpeg");
        response.setHeader("Pragma", "no-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);

        CaptchaUtils imgUtil = CaptchaUtils.instance(10);
        setCache(IMAGE, imgUtil.getCode());
        imgUtil.write(response.getOutputStream());
    }

    @GetMapping(value = "/checkImageCode")
    @ApiOperation(value = "校验图片验证码输入是否正确")
    public boolean loginCheckImageCode(@RequestParam(value = "imgCode", defaultValue = "0") String imageCode) {
        return imageCode.equalsIgnoreCase((String) getCache(IMAGE));
    }


    @ApiOperation(value = "获取短信验证码")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "phone", value = "手机号", paramType = "query", dataType = "String", required = true, example = "13980659617"),
            @ApiImplicitParam(name = "imageCode", value = "图片验证码", paramType = "query", dataType = "String", required = true),
            @ApiImplicitParam(name = "type", value = "获取验证码类型，1-注册获取验证码，2-登录获取验证码,不传则为2", paramType = "query", dataType = "Integer", example = "2")})
    @GetMapping(value = "/loginBySmsCode")
    public String getVerifyCode(String phone, String imageCode, @RequestParam(defaultValue = "2") Integer type) throws Exception {
        checkImageCode(imageCode);
        String smsCode = SMSConfig.code();
        setCache(SMS, smsCode);
        smsService.sendSMS(phone, SMSConfig.getContent(type, smsCode));
        return smsCode;
    }

    private void checkImageCode(String imageCode) {
        String smsCode = (String) getCache(IMAGE);
        if (StringUtils.isEmpty(imageCode) || !imageCode.equalsIgnoreCase(smsCode)) {
            throw new RuntimeException("图片验证码填写错误！");
        }
        //只使用一次
        setCache(IMAGE, null);
    }

    private void checkVerifyCode(String verifyCode) {
        String smsCode = (String) getCache(SMS);
        if (StringUtils.isEmpty(verifyCode) || !verifyCode.equalsIgnoreCase(smsCode)) {
            throw new RuntimeException("验证码输入错误！");
        }
        //只使用一次
        setCache(SMS, null);
    }


    @ApiOperation(value = "注册用户", notes = "通过手机注册，需传入手机号、密码、短信验证码，前端自行校验图片验证是否通过！")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "phone", value = "手机号", paramType = "query", dataType = "String", example = "13980659617", required = true),
            @ApiImplicitParam(name = "password", value = "MD5加密密码，请不要直接传入明文密码！", paramType = "query", dataType = "String", required = true),
            @ApiImplicitParam(name = "smsCode", value = "短信验证码", paramType = "query", dataType = "String")})
    @PostMapping(value = "/registerByPhone")
    public Account register(String phone, String password, String smsCode) {
        if (StringUtils.isEmpty(phone) || StringUtils.isEmpty(password) || StringUtils.isEmpty(smsCode)) {
            throw new RuntimeException("手机号、密码、验证码任意一项都不能为空！");
        }
        checkVerifyCode(smsCode);
        userService.registerUser(phone, password);
//            注册后自动登录
        return loginInternal(phone, "withoutPwd", true);
    }

    @ApiOperation(value = "手机验证码登录", notes = "通过手机验证码登录系统")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "phone", value = "手机号", paramType = "query", dataType = "String", example = "13980659617", required = true),
            @ApiImplicitParam(name = "smsCode", value = "短信验证码", paramType = "query", dataType = "String")})
    @PostMapping("/loginByPhone")
    public Account loginByPhoneVerifyCode(String phone, String smsCode) {
        if (StringUtils.isEmpty(phone) || StringUtils.isEmpty(smsCode)) {
            throw new RuntimeException("手机号或验证码不能为空！");
        }
        checkVerifyCode(smsCode);
        return loginInternal(phone, "without", true);
    }

    @ApiOperation(value = "手机密码登录", notes = "使用手机号+MD5加密密码进行登录，前端自行校验图片验证是否通过！")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "phone", value = "手机号", paramType = "query", dataType = "String", example = "13980659617", required = true),
            @ApiImplicitParam(name = "password", value = "MD5加密密码，请不要直接传入明文密码！", paramType = "query", dataType = "String", required = true, example = "1234")})
    @PostMapping("/loginByPhonePwd")
    public Account loginByPhonePwd(String phone, String password) {
        return loginInternal(phone, password, false);
    }

    private Account loginInternal(String phone, String password, boolean withoutPwd) {
        Account account = loginService.loginInternal(phone, password, withoutPwd);
        Utils.runSilently(() -> {
            String clientType = request.getHeader("clientType");
            if ("manage".equals(clientType)) {
                OperateLog operateLog = new OperateLog();
                operateLog.setUser(account);
                operateLog.setDescription("%s登录了系统" + account.getAccountName());
                operateLogRepository.save(operateLog);
            }
        });
        setCache(USERINFO, account);
        setCache("hospitalProvider", request.getHeader("hospitalProvider"));
        return account;
    }

    @ApiOperation(value = "退出登录")
    @GetMapping("/loginOut")
    public boolean loginOut() {
        SecurityUtils.getSubject().logout();
        Utils.runSilently(() -> {
            Account account = userService.getAccountById(getUserId());
            String clientType = request.getHeader("clientType");
            if ("manage".equals(clientType)) {
                OperateLog operateLog = new OperateLog();
                operateLog.setUser(account);
                operateLog.setDescription("%s登出了系统" + account.getAccountName());
                operateLogRepository.save(operateLog);
            }
        });
        return true;
    }
}
